package com.mx.restful.view.window.frame;

import cn.hutool.core.map.MapUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONStrFormatter;
import cn.hutool.json.JSONUtil;
import com.mx.restful.beans.HttpMethod;
import com.mx.restful.beans.Request;
import com.mx.restful.service.Notify;
import com.mx.restful.utils.JsonUtil;
import com.mx.restful.utils.RequestUtils;
import com.mx.restful.utils.RestUtil;
import com.mx.restful.utils.SystemUtil;
import com.mx.restful.utils.convert.ParamConvert;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.ComboBox;
import com.intellij.openapi.ui.JBPopupMenu;
import com.intellij.psi.PsiInvalidElementAccessException;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.ui.components.JBTabbedPane;
import com.intellij.ui.components.JBTextField;
import org.apache.commons.lang3.StringUtils;
import org.jdesktop.swingx.JXButton;
import org.jdesktop.swingx.JXEditorPane;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;


/**
 * @Author: mengxiang.
 * @Date: 2020/6/22.
 * @Time: 11:37 上午.
 * @Description:
 */
public class RestDetail extends JPanel {

    private static final int REQUEST_TIMEOUT = 1000 * 10;

    private final Project project;
    private final ThreadPoolExecutor poolExecutor;
    public static ParamConvert convert;

    /**
     * 下拉框 - 选择选择请求方法
     */
    private JComboBox<HttpMethod> requestMethod;
    /**
     * 输入框 - url地址
     */
    private JTextField requestUrl;
    /**
     * 按钮 - 发送请求
     */
    private JButton sendRequest;
    /**
     * 选项卡面板 - 请求信息
     */
    private JTabbedPane tabbedPane;
    /**
     * 文本域 - 请求头
     */
    private JEditorPane requestHead;
    /**
     * 文本域 - 请求体
     */
    private JEditorPane requestBody;
    /**
     * 标签 - 显示返回结果
     */
    private JEditorPane responseView;

    private DetailHandle callback;

    private Request chooseRequest;

    /**
     * 请求头缓存
     */
    public static Map<Request, String> headersCache = new HashMap<>();

    /**
     * 参数缓存
     */
    public static Map<Request, String> bodyCache = new HashMap<>();

    //缓存文件位置
    private File file;

    public RestDetail(@NotNull Project project) {
        this.project = project;
        poolExecutor = new ThreadPoolExecutor(
                1,
                1,
                1000,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(8),
                new ThreadPoolExecutor.DiscardOldestPolicy()
        );
        // this.convert = new DefaultConvert();
        this.convert = new ParamConvert();

        initView();

        initEvent();
    }

    private void initView() {
        setLayout(new BorderLayout(0, 0));

        JPanel panelInput = new JPanel();
        add(panelInput, BorderLayout.NORTH);
        panelInput.setLayout(new BorderLayout(0, 0));

        requestMethod = new ComboBox<>(HttpMethod.getValues());
        panelInput.add(requestMethod, BorderLayout.WEST);

        requestUrl = new JBTextField();
        panelInput.add(requestUrl);
        requestUrl.setColumns(45);

        sendRequest = new JXButton("发送请求");
        panelInput.add(sendRequest, BorderLayout.EAST);

        tabbedPane = new JBTabbedPane(JTabbedPane.TOP);
        add(tabbedPane, BorderLayout.CENTER);

        JScrollPane scrollPaneHead = new JBScrollPane();
        scrollPaneHead.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        tabbedPane.addTab("请求头", scrollPaneHead);
        requestHead = new JXEditorPane();
        scrollPaneHead.setViewportView(requestHead);

        JScrollPane scrollPaneBody = new JBScrollPane();
        scrollPaneBody.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        tabbedPane.addTab("参数", scrollPaneBody);
        requestBody = new JXEditorPane();
        scrollPaneBody.setViewportView(requestBody);

        JScrollPane scrollPane = new JBScrollPane();
        scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        tabbedPane.addTab("响应", scrollPane);
        responseView = new JEditorPane();
        scrollPane.setViewportView(responseView);
    }

    /**
     * 初始化事件
     */
    private void initEvent() {
        // 发送请求按钮监听
        sendRequest.addActionListener(event -> {
            // 选择Response页面
            tabbedPane.setSelectedIndex(2);

            HttpMethod method = (HttpMethod) requestMethod.getSelectedItem();
            if (method == null) {
                method = HttpMethod.GET;
            }
            String url = requestUrl.getText();

            if (url == null || "".equals(url.trim())) {
                responseView.setText("请求路径不能为空");
                return;
            }

            String head = requestHead.getText();
            String body = requestBody.getText();
            boolean scanCacheFile = RestUtil.scanCacheType(project, chooseRequest.getPsiMethod().getResolveScope());
            if (scanCacheFile) {
                if (file == null || !file.exists()) {
                    File fileDir = new File(project.getBasePath(), ".restful");
                    if (!fileDir.exists()) {
                        fileDir.mkdir();
                    }
                    file = new File(fileDir.getPath(), "restful.json");
                }
                JSONObject json = JSONUtil.readJSONObject(file, Charset.defaultCharset());
                String headKey = url + "_" + method.name().toUpperCase(Locale.ROOT) + "_head";
                String bodyKey = url + "_" + method.name().toUpperCase(Locale.ROOT) + "_body";
                json.putOpt(headKey, head);
                json.putOpt(bodyKey, body);
                FileWriter fileWriter = null;
                try {
                    fileWriter = new FileWriter(file);
                    json.write(fileWriter);
//                    fileWriter.write(JSONUtil.toJsonStr(json));
                    fileWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }


            } else {
                if (StringUtils.isNotBlank(head)) {
                    headersCache.put(chooseRequest, JsonUtil.formatJson((Objects.requireNonNull(JsonUtil.formatMap(head)))));
                }
                if (StringUtils.isNotBlank(body)) {
                    bodyCache.put(chooseRequest, JsonUtil.formatJson((Objects.requireNonNull(JsonUtil.formatMap(body)))));
                }
            }
            responseView.setText(" -> 请求正在发送");
            HttpMethod finalMethod = method;
            poolExecutor.execute(() -> {
                String resp;
                try {
                    resp = RequestUtils.request(url, finalMethod, head, body);
                } catch (Exception e) {
                    e.printStackTrace();
                    resp = e.getMessage();
                }
                responseView.setText(formatJson(resp));
            });
        });

        responseView.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseReleased(MouseEvent e) {
                if (SwingUtilities.isRightMouseButton(e)) {
                    popupMenu(responseView, e.getX(), e.getY());
                }
                super.mouseReleased(e);
            }
        });
    }

    public void setRequest(Request request) {
        chooseRequest = request;
        HttpMethod selItem = HttpMethod.GET;
        String reqUrl = "";
        String reqBody = "";

        try {
            if (request != null) {
                GlobalSearchScope scope = request.getPsiMethod().getResolveScope();
                reqUrl = RestUtil.getRequestUrl("http",
                        RestUtil.scanListenerPort(project, scope), "",
                        request.getPath()
                );

                // 选择Body页面
                tabbedPane.setSelectedIndex(1);

                selItem = request.getMethod() == null || request.getMethod() == HttpMethod.REQUEST ?
                        HttpMethod.GET : request.getMethod();

                convert.setPsiMethod(request.getPsiMethod());
                reqBody = convert.formatString();
            }
        } catch (PsiInvalidElementAccessException e) {
            if (callback != null) {
                callback.handle();
            }
        }


        requestMethod.setSelectedItem(selItem);
        requestUrl.setText(reqUrl);
        boolean cacheFile = RestUtil.scanCacheType(project, request.getPsiMethod().getResolveScope());
        if (cacheFile) {
            File fileDir = new File(project.getBasePath(), ".restful");
            if (!fileDir.exists()) {
                fileDir.mkdir();
            }
            file = new File(fileDir.getPath(), "restful.json");
            if (!file.exists()) {
                try {
                    FileWriter fileWriter = new FileWriter(file);
                    fileWriter.write("{}");
                    fileWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            JSONObject json = JSONUtil.readJSONObject(file, Charset.defaultCharset());
            String headKey = reqUrl + "_" + request.getMethod().name().toUpperCase(Locale.ROOT) + "_head";
            String bodyKey = reqUrl + "_" + request.getMethod().name().toUpperCase(Locale.ROOT) + "_body";
            if (json.containsKey(headKey)) {
                requestHead.setText(json.get(headKey) != null ? json.get(headKey).toString() : "");
            } else {
                Map<String, String> requestHeaderMap = RestUtil.scanListenerRequestHeaders(project, request.getPsiMethod().getResolveScope());
                if (MapUtil.isNotEmpty(requestHeaderMap)) {
                    requestHead.setText(JsonUtil.formatJson(requestHeaderMap));
                }
            }

            if (json.containsKey(bodyKey)) {
                requestBody.setText(json.get(bodyKey) != null ? json.get(bodyKey).toString() : "");
            } else {
                requestBody.setText(reqBody);
            }
        } else {
            //包含
            if (headersCache.containsKey(request)) {
                requestHead.setText(headersCache.get(request));
            } else {
                Map<String, String> requestHeaderMap = RestUtil.scanListenerRequestHeaders(project, request.getPsiMethod().getResolveScope());
                if (MapUtil.isNotEmpty(requestHeaderMap)) {
                    requestHead.setText(JsonUtil.formatJson(requestHeaderMap));
                }
            }

            //包含
            if (bodyCache.containsKey(request)) {
                requestBody.setText(bodyCache.get(request));
            } else {
                requestBody.setText(reqBody);
            }
        }


    }

    public void setCallback(DetailHandle callback) {
        this.callback = callback;
    }


    /**
     * 显示右键菜单
     *
     * @param component component
     * @param x         横坐标
     * @param y         纵坐标
     */
    private void popupMenu(@NotNull JComponent component, int x, int y) {
        JPopupMenu menu = new JBPopupMenu();
        ActionListener actionListener = actionEvent -> {
            String responseViewText = responseView.getText();
            switch (((JMenuItem) actionEvent.getSource()).getMnemonic()) {
                case 0:
                    if (responseViewText != null && responseViewText.trim().length() > 0) {
                        SystemUtil.setClipboardString(responseViewText);
                        Notify.getInstance(project).info("结果复制成功");
                    }
                    break;
                case 1:
                    responseView.setText(formatJson(responseViewText));
                    break;
                default:
            }
        };

        JMenuItem copyResponse = new JMenuItem("复制结果", AllIcons.Actions.Copy);
        copyResponse.setMnemonic(0);
        copyResponse.addActionListener(actionListener);
        menu.add(copyResponse);

        JMenuItem formatResponse = new JMenuItem("格式化结果", AllIcons.Actions.Refresh);
        formatResponse.setMnemonic(1);
        formatResponse.addActionListener(actionListener);
        menu.add(formatResponse);

        menu.show(component, x, y);
    }

    private String formatJson(@Nullable String resp) {
        if (resp != null) {

            if (JsonUtil.isJsonObj(resp) || JsonUtil.isJsonArray(resp)) {
                resp = JSONStrFormatter.format(resp.trim());
            }
        }
        return resp;
    }

    public interface DetailHandle {

        /**
         * 处理逻辑
         */
        void handle();
    }
}
